package it.uniroma2.art.coda.main;

import it.uniroma2.art.coda.core.CODACore;
import it.uniroma2.art.coda.exception.FelixInitializationException;
import it.uniroma2.art.coda.exception.PRParserException;
import it.uniroma2.art.coda.interfaces.IdentityResolutionInterface;
import it.uniroma2.art.coda.interfaces.ProjectionRulesDeciderInterface;
import it.uniroma2.art.coda.interfaces.SmartSuggestionInterface;
import it.uniroma2.art.coda.projectionrule.PlaceholderStruct;
import it.uniroma2.art.coda.projectionrule.ProjectionRule;
import it.uniroma2.art.coda.structures.ARTTriple;
import it.uniroma2.art.coda.structures.BindLabelToExistingARTURIResource;
import it.uniroma2.art.coda.structures.CodaFinalSuggestions;
import it.uniroma2.art.coda.structures.PreviousDecisionSingleElement;
import it.uniroma2.art.coda.structures.PreviousDecisions;
import it.uniroma2.art.coda.structures.SelectedProjectionRules;
import it.uniroma2.art.coda.structures.SmartSuggestionStruct;
import it.uniroma2.art.coda.structures.SuggOntologyCoda;
import it.uniroma2.art.owlart.exceptions.ModelAccessException;
import it.uniroma2.art.owlart.exceptions.ModelCreationException;
import it.uniroma2.art.owlart.exceptions.ModelUpdateException;
import it.uniroma2.art.owlart.exceptions.QueryEvaluationException;
import it.uniroma2.art.owlart.exceptions.UnsupportedQueryLanguageException;
import it.uniroma2.art.owlart.exceptions.UnsupportedRDFFormatException;
import it.uniroma2.art.owlart.io.RDFFormat;
import it.uniroma2.art.owlart.model.ARTLiteral;
import it.uniroma2.art.owlart.model.ARTNode;
import it.uniroma2.art.owlart.model.ARTURIResource;
import it.uniroma2.art.owlart.model.NodeFilters;
import it.uniroma2.art.owlart.models.OWLArtModelFactory;
import it.uniroma2.art.owlart.models.OWLModel;
import it.uniroma2.art.owlart.models.RDFModel;
import it.uniroma2.art.owlart.models.UnloadableModelConfigurationException;
import it.uniroma2.art.owlart.models.UnsupportedModelConfigurationException;
import it.uniroma2.art.owlart.models.conf.ModelConfiguration;
import it.uniroma2.art.owlart.query.MalformedQueryException;
import it.uniroma2.art.owlart.sesame2impl.factory.ARTModelFactorySesame2Impl;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.uima.UIMAFramework;
import org.apache.uima.analysis_engine.AnalysisEngine;
import org.apache.uima.analysis_engine.AnalysisEngineProcessException;
import org.apache.uima.jcas.JCas;
import org.apache.uima.pear.tools.PackageBrowser;
import org.apache.uima.pear.tools.PackageInstaller;
import org.apache.uima.resource.ResourceInitializationException;
import org.apache.uima.resource.ResourceSpecifier;
import org.apache.uima.util.InvalidXMLException;
import org.apache.uima.util.XMLInputSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class CompleteTest {

	// private static CODACore codaCore = null;

	//private String aggregateAEFilePath = "E:/CODATest/provaAggregateAEPub.xml";

	// private static String txtFilePath = "E:/CODATest/test.txt";
	// private static String htmlFilePath = "E:/CODATest/andreaRedux.html";

	static private String[] htmlFilePathArray = { "E:/CODATest/htmlPublication/Andrea.htm",
			"E:/CODATest/htmlPublication/Armando.htm", "E:/CODATest/htmlPublication/Noemi.htm",
			"E:/CODATest/htmlPublication/Danilo.htm" };

	private String dirComponentsPath = "E:/CODATest/components";

	// private String textToBeAnnotatate;

	private String prFilePath = "E:/CODATest/provaPR.pr";

	private String oSGiDirPath = "E:/CODATest/OSGiCache";

	private String repositoryDirPath = "E:/CODATest/repDir";
	// private String repositoryDirPath =
	// "C:/Users/Andrea/AppData/Roaming/Mozilla/Firefox/Profiles/ks569oks.default/SemanticTurkeyData/projects/pub/store";

	private String baseUri = "http://art.uniroma2.it";
	// private static String importedUri = "http://viaggio";
	private String importedUri = "http://PersonEmail";

	// private static String rdfInputFilePath = "E:/CODATest/rdfFile.owl";
	// private String rdfInputFilePath = "E:/CODATest/PersonEmail.owl";
	private String rdfInputFilePath = "E:/CODATest/Publication.owl";

	private String rdfOutputFilePath = "E:/CODATest/PublicationOutPut.owl";

	private static Logger logger = LoggerFactory.getLogger(CompleteTest.class);

	private Map<String, ProjectionRulesDeciderInterface> pdaMap = new HashMap<String, ProjectionRulesDeciderInterface>();
	private Map<String, IdentityResolutionInterface> idaMap = new HashMap<String, IdentityResolutionInterface>();
	private Map<String, SmartSuggestionInterface> ssMap = new HashMap<String, SmartSuggestionInterface>();

	private PreviousDecisions prevDec = new PreviousDecisions();

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		logger.info("program started");
		CompleteTest completeTest = new CompleteTest();
		OWLModel owlModel = null;
		CODACore codaCore = null;
		try {

			
			String pearPathString = "E:\\CODATest\\publication.pear";
			String installedPearString = "E:\\CODATest\\installedPear";
			String descrPathString = completeTest.installPear(pearPathString, installedPearString);
			
			// Create an OWLModel and the triple Store.
			owlModel = completeTest.initializeOWLModel();

			// Initialize CODACORE
			codaCore = completeTest.initializeCODACore(null, owlModel);

			// set the 3 maps containing all the three different type of modules
			completeTest.setMap(codaCore);

			// choose the 3 selected modules
			completeTest.setSelectedModule(codaCore);

			// Printing the projection rule

			if (logger.isDebugEnabled())
				codaCore.getProjRuleModel().printModel();

			for (int i = 0; i < htmlFilePathArray.length; ++i) {
				// read the text which will be pass to the UIMA AAE
				logger.info("parsing file = " + htmlFilePathArray[i]); // da cancellare
				String textToBeAnnotatate = completeTest.getTextToBeAnnotated(htmlFilePathArray[i]);

				// use the UIMA AAE to annotate the text
				JCas annotCas = completeTest.analyzeText(descrPathString, textToBeAnnotatate);

				// set the jcas in CODA
				codaCore.setJCas(annotCas);

				// process all the UIMA annotation
				completeTest.processUIMAAnnotation(codaCore, owlModel);
			}

			// Save the ontology
			completeTest.saveRDF(owlModel);

		} catch (IOException e) {
			e.printStackTrace();
		} catch (InvalidXMLException e) {
			e.printStackTrace();
		} catch (ResourceInitializationException e) {
			e.printStackTrace();
		} catch (AnalysisEngineProcessException e) {
			e.printStackTrace();
		} catch (ModelCreationException e) {
			e.printStackTrace();
		} catch (FelixInitializationException e) {
			e.printStackTrace();
		} catch (ModelAccessException e) {
			e.printStackTrace();
		} catch (ModelUpdateException e) {
			e.printStackTrace();
		} catch (UnsupportedRDFFormatException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (PRParserException e) {
			e.printStackTrace();
		} catch (UnsupportedModelConfigurationException e) {
			e.printStackTrace();
		} catch (UnloadableModelConfigurationException e) {
			e.printStackTrace();
		} catch (UnsupportedQueryLanguageException e) {
			e.printStackTrace();
		} catch (MalformedQueryException e) {
			e.printStackTrace();
		} catch (QueryEvaluationException e) {
			e.printStackTrace();
		} finally {
			try {
				if (codaCore != null)
					codaCore.stopAndClose();
			} catch (ModelUpdateException e) {
				e.printStackTrace();
			}
			logger.info("Program termnated"); // da cancellare
		}
		return;
	}
	
	
	public String installPear(String pearPathString, String installedPearString) throws IOException {
		File pearFile = new File(pearPathString);
		File installDir = new File(installedPearString);
		if (installDir.exists()) {
			this.deleteDirectory(installDir);
		}
		PackageBrowser instPear = PackageInstaller.installPackage(installDir, pearFile, true);
		return instPear.getComponentPearDescPath();
	}

	private boolean deleteDirectory(File path) {
		if (path.exists()) {
			File[] files = path.listFiles();
			for (int i = 0; i < files.length; i++) {
				if (files[i].isDirectory()) {
					deleteDirectory(files[i]);
				} else {
					files[i].delete();
				}
			}
		}
		return (path.delete());
	}

	private String getTextToBeAnnotated(String htmlFilePath) throws IOException {
		// read the input file containig the test to be analized
		InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream(htmlFilePath),
				"UTF-8");
		BufferedReader br = new BufferedReader(inputStreamReader);

		StringBuilder contents = new StringBuilder();
		String line;

		while ((line = br.readLine()) != null) {
			contents.append(line);
			contents.append(System.getProperty("line.separator"));
		}
		return contents.toString();
	}

	private JCas analyzeText(String descrPathString, String textToBeAnnotatate) throws IOException,
			ResourceInitializationException, AnalysisEngineProcessException, InvalidXMLException {
		// pass the txt read to the AE (which is an AAE). To do this read the AAE descriptor and then execute
		// the AAE
		XMLInputSource in;
		ResourceSpecifier specifier;
		AnalysisEngine ae;
		JCas annotCas;

		//in = new XMLInputSource(aggregateAEFilePath);
		in = new XMLInputSource(descrPathString);
		specifier = UIMAFramework.getXMLParser().parseResourceSpecifier(in);
		ae = UIMAFramework.produceAnalysisEngine(specifier);
		ae.setConfigParameterValue("Encoding", "UTF-8");
		annotCas = ae.newJCas();
		annotCas.setDocumentText(textToBeAnnotatate);
		ae.process(annotCas);
		return annotCas;
	}

	private OWLModel initializeOWLModel() throws ModelUpdateException, FileNotFoundException, IOException,
			ModelAccessException, UnsupportedRDFFormatException, ClassNotFoundException,
			ModelCreationException, InstantiationException, IllegalAccessException,
			UnsupportedModelConfigurationException, UnloadableModelConfigurationException {

		/*
		 * String owlArtModelFactoryImplClassName =
		 * "it.uniroma2.art.owlart.sesame2impl.factory.ARTModelFactorySesame2Impl"; Class<? extends
		 * ModelFactory> owlArtModelFactoryImplClass = (Class<? extends ModelFactory>)
		 * Class.forName(owlArtModelFactoryImplClassName); OWLArtModelFactory artModelFact =
		 * OWLArtModelFactory.createModelFactory( owlArtModelFactoryImplClass.newInstance());
		 */
		OWLArtModelFactory artModelFact = OWLArtModelFactory
				.createModelFactory(new ARTModelFactorySesame2Impl());
		String mcClassName = "it.uniroma2.art.owlart.sesame2impl.models.conf.Sesame2PersistentInMemoryModelConfiguration";
		Class mcClass = Class.forName(mcClassName);
		ModelConfiguration modelConf = artModelFact.createModelConfigurationObject(mcClass);
		OWLModel owlModel = artModelFact.loadOWLModel(baseUri, repositoryDirPath, modelConf);
		owlModel.setBaseURI(baseUri);
		owlModel.setDefaultNamespace(baseUri + "#");
		owlModel.clearRDF();
		owlModel.addRDF(new File(rdfInputFilePath), importedUri, RDFFormat.RDFXML, NodeFilters.MAINGRAPH);

		return owlModel;
	}

	private CODACore initializeCODACore(JCas annotCas, OWLModel owlModel)
			throws FelixInitializationException, PRParserException {
		File oSGiDir = new File(oSGiDirPath);
		CODACore codaCore = new CODACore();
		codaCore.initialize(annotCas, oSGiDir, dirComponentsPath, false, prFilePath, owlModel, prevDec);
		return codaCore;
	}

	private void setMap(CODACore codaCore) {
		pdaMap = codaCore.getProjectionDisambiguationAnnotation();
		idaMap = codaCore.getIdentityResolutionAnnotationMap();
		ssMap = codaCore.getSmartSuggestionMap();
	}

	private void setSelectedModule(CODACore codaCore) {
		// Choose the 5 components from the 5 lists, at the moment the first of the lists which are not null
		// are choosen
		String key;
		if (pdaMap.isEmpty() == false) {
			key = pdaMap.keySet().iterator().next();
			ProjectionRulesDeciderInterface pda = pdaMap.get(key);
			codaCore.setProjectionDisambiguationAnnotation(pda);
		}
		if (idaMap.isEmpty() == false) {
			key = idaMap.keySet().iterator().next();
			IdentityResolutionInterface ida = idaMap.get(key);
			codaCore.setIdentityResolutionAnnotation(ida);
		}
		if (ssMap.isEmpty() == false) {
			key = ssMap.keySet().iterator().next();
			SmartSuggestionInterface ss = ssMap.get(key);
			codaCore.setSmartSuggestion(ss);
		}
	}

	private void processUIMAAnnotation(CODACore codaCore, OWLModel owlModel) throws ModelUpdateException,
			UnsupportedQueryLanguageException, ModelAccessException, MalformedQueryException,
			QueryEvaluationException {
		SuggOntologyCoda suggOntCoda;
		// PrevAnnProjectedList prevAnnProjList = new PrevAnnProjectedList(null);
		while (codaCore.isAnotherAnnotationPrsent()) {
			logger.debug("\n\n");

			suggOntCoda = codaCore.processNextAnnotation();
			logger.debug(suggOntCoda.getAnnotation().getCoveredText() + " type: "
					+ suggOntCoda.getAnnotation().getType().toString() + "\t"
					+ suggOntCoda.getAnnotation().getBegin() + " -> " + suggOntCoda.getAnnotation().getEnd());

			SelectedProjectionRules selProjRules = suggOntCoda.getSelProjRules();
			BindLabelToExistingARTURIResource bindLabels = suggOntCoda.getBindLabels();
			SmartSuggestionStruct smartSuggs = suggOntCoda.getSmartSuggestions();
			CodaFinalSuggestions codaSuggs = suggOntCoda.getCodaFinalSuggs();
			
			logger.debug("%%%Selected Projection Rule:");
			List<ProjectionRule> projRulesList = selProjRules.getProjRuleList();
			for (ProjectionRule projRule : projRulesList) {
				logger.debug("\ttype = " + projRule.getUIMAType() + "\tid: " + projRule.getId());

				logger.debug("%%%Bind Labels:");
				Map<PlaceholderStruct, Map<String, ARTURIResource>> bindMap = bindLabels
						.getPlaceholderToARTURIResMap();
				Iterator<PlaceholderStruct> bindNodeIter = bindMap.keySet().iterator();
				while (bindNodeIter.hasNext()) {
					PlaceholderStruct node = bindNodeIter.next();
					Map<String, ARTURIResource> artUriResMap = bindMap.get(node);
					logger.debug("\t" + node.getName());
					for (ARTURIResource artUriRes : artUriResMap.values())
						logger.debug("\t\t" + artUriRes.getURI());
				}
				
				logger.debug("%%%Smart Suggestion:");
				Map<PlaceholderStruct, Map<String, ARTURIResource>> smarSugMap = smartSuggs
						.getPlaceholderToARTURIResMap();
				Iterator<PlaceholderStruct> smartSuggIter = smarSugMap.keySet().iterator();
				while (smartSuggIter.hasNext()) {
					PlaceholderStruct node = smartSuggIter.next();
					Map<String, ARTURIResource> artUriResMap = smarSugMap.get(node);
					logger.debug("\t" + node.getName());
					for (ARTURIResource artUriRes : artUriResMap.values())
						logger.debug("\t\t" + artUriRes.getURI());
				}

				logger.debug("%%%Suggested Triple:");
				List<ARTTriple> artTripleList = codaSuggs.getTriplesList();
				for (ARTTriple artTriple : artTripleList) {
					logger.debug("\tTriple:");
					ARTURIResource subjUri = artTriple.getSubjectUri();
					logger.debug("\t\t" + subjUri.getURI());
					ARTURIResource predUri = artTriple.getPredicateUri();
					logger.debug("\t\t" + predUri.getURI());
					if (artTriple.isObjARes()) {
						ARTURIResource objUri = artTriple.getObjectUri();
						logger.debug("\t\t" + objUri.getURI() + "\tURI");
					} else {
						ARTLiteral objLit = artTriple.getObjectLiteral();
						logger.debug("\t\t" + objLit.getLabel() + "\tLiteral");
					}
				}
			}
			// add the suggestion and the just added triple to the prevDec
			List<ARTTriple> addedTripleList = new ArrayList<ARTTriple>();
			for (ARTTriple artTriple : suggOntCoda.getCodaFinalSuggs().getTriplesList()) {
				ARTURIResource subject = artTriple.getSubjectUri();
				ARTURIResource predicate = artTriple.getPredicateUri();
				ARTNode object;
				if (artTriple.isObjARes()) {
					object = artTriple.getObjectUri();
				} else { // artTriple.isObjARes == false
					object = artTriple.getObjectLiteral();
				}
				owlModel.addTriple(subject, predicate, object);
				addedTripleList.add(artTriple);
			}
			PreviousDecisionSingleElement prevDecSingleElem = new PreviousDecisionSingleElement(
					addedTripleList, suggOntCoda);
			prevDec.addPrevDecSingleElem(prevDecSingleElem);

		}
	}

	private void saveRDF(OWLModel owlModel) throws IOException, ModelAccessException,
			UnsupportedRDFFormatException {
		owlModel.writeRDF(new File(rdfOutputFilePath), RDFFormat.RDFXML, NodeFilters.MAINGRAPH);
	}
}
